package org.wjk.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.wjk.filter.JwtTokenParse;


@Configuration
@RequiredArgsConstructor
@EnableWebSecurity/*开启SpringSecurity鉴权*/
@EnableGlobalMethodSecurity(prePostEnabled = true)/*指定访问controller方法鉴权*/
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    private final UserDetailsService detailsService;
    private final AuthenticationFailureHandler failureHandler;
    private final AuthenticationSuccessHandler successHandler;
    private final AuthenticationEntryPoint entryPoint;
    private final AccessDeniedHandler deniedHandler;
    private final JwtTokenParse tokenParse;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        //主要用于认证管理器的配置： 指定userDetailService的实现类，制定passwordEncoded的实现
        auth.userDetailsService(detailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception
    {
        //配置指定的路径不经过认证链
        web.ignoring().antMatchers("/image/**","/captcha");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        //完成对认证链的配置
        http.formLogin() //指定:登录方式是以form表单登录
                .loginProcessingUrl("/login") //指定:处理登录请求的URL
                .failureHandler(failureHandler)
                .successHandler(successHandler)
                .and() //返回一个httpSecurity对象
                .csrf().disable() //由于使用了JWTtoken,而不使用coockie保存认证信息,因此不需要跨站请求的验证:关闭跨站请求伪造验证
                .cors() //指定:springSecurity允许跨域访问
                .and()
                .sessionManagement() //设置session的使用:由于使用JWTtoken,服务器端不需要使用session保存用户登录后的信息
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) //关闭session
                .and()
                .authorizeRequests() //指定:认证授权相关信息
                .antMatchers("/login").permitAll() //请求login时不需要登录
                .anyRequest().authenticated()//剩下的所有请求都需要登录
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(entryPoint)
                .accessDeniedHandler(deniedHandler)
                .and()
                .addFilterBefore(tokenParse,UsernamePasswordAuthenticationFilter.class)
        ;
    }
}
